package org.harsh.transmission.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.ShiroUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.tbxt.domain.BizSystem;
import com.ruoyi.tbxt.service.IBizSysService;
import com.ruoyi.web.controller.common.CommonController;
import io.swagger.annotations.*;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.collections4.KeyValue;
import org.harsh.common.Config;
import org.harsh.common.Util;
import org.harsh.transmission.common.TaskType;
import org.harsh.transmission.domain.TransMsg;
import org.harsh.transmission.domain.TransReceiver;
import org.harsh.transmission.domain.TransTask;
import org.harsh.transmission.service.ITransMsgService;
import org.harsh.transmission.service.ITransReceiverService;
import org.harsh.transmission.service.ITransTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

@Api("业务系统接口")
@RestController
@RequestMapping("/bizSys/api")
public class TransMsgInfController extends BaseController {
    private static final Log log = Log.get();
    @Autowired
    private ITransMsgService transMsgService;
    @Autowired
    private ITransReceiverService transReceiverService;
    @Autowired
    private ITransTaskService transTaskService;
    @Autowired
    private ISysDeptService sysDeptService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private IBizSysService bizSysService;

    @Setter
    @Getter
    @ApiModel(value = "NodeEntity", description = "节点实体")
    public static class NodeEntity {
        @ApiModelProperty("节点ID")
        private long nodeId;

        @ApiModelProperty("节点名称")
        private String nodeName;

        @ApiModelProperty("节点地址")
        private String nodeAddr;

        public NodeEntity() {
        }

        public NodeEntity(long nodeId, String nodeName, String nodeAddr) {
            this.nodeId = nodeId;
            this.nodeName = nodeName;
            this.nodeAddr = nodeAddr;
        }
    }

    @Setter
    @Getter
    @ApiModel(value = "MsgEntity", description = "消息实体")
    public static class MsgEntity {
        @ApiModelProperty("业务系统编号")
        private String bizSysCode;
        @ApiModelProperty("消息编号")
        private long msgId;
        @ApiModelProperty("任务类型")
        private int taskType;
        @ApiModelProperty("接收节点")
        private String receivers;
        @ApiModelProperty("消息内容")
        private String msgData;
        @ApiModelProperty("文件列表")
        private String msgFiles;

        public MsgEntity(int taskType, String receivers, String msgData, String msgFiles) {
            this.taskType = taskType;
            this.receivers = receivers;
            this.msgData = msgData;
            this.msgFiles = msgFiles;
        }
    }

    @ApiOperation("获取节点列表")
    @GetMapping("/getNodeList")
    public R<List<NodeEntity>> getNodeList() {
        List<NodeEntity> nodeList = new ArrayList<NodeEntity>();
        List<SysDept> depts = sysDeptService.selectDeptList();
        for (SysDept dept : depts) {
            NodeEntity node = new NodeEntity();
            node.setNodeId(dept.getDeptId());
            node.setNodeName(dept.getDeptName());
            node.setNodeAddr(dept.getLocalAddr());
            nodeList.add(node);
        }
        return R.ok(nodeList);
    }

    @ApiOperation("发送消息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "taskType", value = "任务类型", dataType = "Integer", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "receivers", value = "接收节点", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "msgData", value = "消息内容", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "bizSysCode", value = "业务系统编号", dataType = "String", dataTypeClass = String.class)
    })
    @PostMapping("/sendData")
    public R<Integer> sendData(MsgEntity msg) {
        BizSystem bizSystem = bizSysService.selectBizByCode(msg.getBizSysCode());
        if(bizSystem == null) {
            return R.fail(500, "接入业务系统编号不正确！");
        }
        String msgData = msg.getMsgData();
        String receivers = msg.getReceivers();
        int taskType = msg.getTaskType();
        if (!TaskType.UNICAST.equals(taskType) && !TaskType.UNIDIRECTIONAL_TRANSMISSION.equals(taskType)) {
            return R.fail(500, "只支持单播和单向传输！");
        }

        if (StrUtil.isBlankOrUndefined(msgData)) {
            return R.fail(500, "消息内容为空！");
        }

        byte[] msgBytes = msgData.getBytes(Config.DEFAULT_CHARSET);
        String msgMd5 = null;
        try {
            msgMd5 = Util.byteArrMD5Str(msgBytes);
        } catch (IOException e) {
            log.error(e, "生成消息MD5失败！");
            return R.fail(500, "生成消息MD5失败！");
        }

//        Set<Long> userList = new HashSet<>();
        Set<Long> deptList = new HashSet<>();
        Map<Long, Long> sysDeptSet = new HashMap<>();
        SysDept sysDept = sysDeptService.loadLocalDept();
//        SysUser currentUser = ShiroUtils.getSysUser();
        for (String recvs : receivers.split(":")) {
            long recvNodeId = Long.parseLong(recvs);
            deptList.add(recvNodeId);
//            }
        }

        TransMsg transMsg = new TransMsg();
        long msgId = (long) Math.abs(cn.hutool.core.lang.UUID.randomUUID().hashCode());
        transMsg.setMsgId(msgId);
        transMsg.setMsgType(0L);
        transMsg.setMsgSize((long) msgBytes.length);
        transMsg.setFromNode(sysDept.getDeptId());
        transMsg.setFromType(1L);
        transMsg.setFromId(bizSystem.getBizId());
        transMsg.setMsgMd5(msgMd5);
        transMsg.setMsgData(msgData);
        transMsgService.insertTransMsg(transMsg);


        for (long deptId : deptList) {
            TransTask task = new TransTask();
            task.setMsgId(msgId);
            task.setTaskPriority((long) bizSystem.getPriority());
            task.setTaskType((long) taskType);
            task.setRecvNode(deptId);
            task.setTaskStatus(0L);
            transTaskService.insertTransTask(task);

            TransReceiver receiver = new TransReceiver();
            receiver.setMsgId(msgId);
            // 接收对象为节点
            receiver.setRecvType(0L);
            receiver.setRecvId(0l);
            receiver.setRecvNode(deptId);
            transReceiverService.insertTransReceiver(receiver);
        }

        return R.ok(200, "" + msgId);
    }

    @ApiOperation("文件上传")
    @PostMapping("/upload")
    public AjaxResult uploadFile(@RequestPart("file") MultipartFile file) throws Exception {
        CommonController bean = SpringUtils.getBean(CommonController.class);
        return bean.uploadFile(file);
    }

    @ApiOperation("发送文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "taskType", value = "任务类型", dataType = "Integer", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "receivers", value = "接收节点", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "msgFiles", value = "文件列表", dataType = "String", dataTypeClass = String.class)
    })
    @PostMapping("/sendFile")
    public R<Integer> sendFile(MsgEntity msg) {
        String receivers = msg.getReceivers();
        int taskType = msg.getTaskType();
        String msgFiles = msg.getMsgFiles();

        if (!TaskType.UNICAST.equals(taskType) && !TaskType.UNIDIRECTIONAL_TRANSMISSION.equals(taskType)) {
            return R.fail(500, "只支持单播和单向传输！");
        }

        if (StrUtil.isBlankOrUndefined(msgFiles)) {
            return R.fail(500, "消息内容为空！");
        }

        SysDept sysDept = sysDeptService.loadLocalDept();
        SysUser currentUser = ShiroUtils.getSysUser();

        // 单播 或 单向传输
        Set<Long> userList = new HashSet<>();
        Set<Long> deptList = new HashSet<>();
        Map<Long, Long> sysDeptSet = new HashMap<>();
        for (String recvs : receivers.split(":")) {
            long userId = Long.parseLong(recvs);
            SysUser tmpUser = sysUserService.selectUserById(userId);
            if (tmpUser.getDeptId().longValue() != sysDept.getDeptId().longValue()) {
                userList.add(userId);
                deptList.add(tmpUser.getDeptId());
                sysDeptSet.put(userId, tmpUser.getDeptId());
            }
        }

        for (String str : msgFiles.split(":")) {
            TransMsg transMsg = new TransMsg();
            long msgId = (long) Math.abs(cn.hutool.core.lang.UUID.randomUUID().hashCode());
            transMsg.setMsgId(msgId);
            transMsg.setMsgType(1L);

            String localPath = RuoYiConfig.getProfile();
            // 数据库资源地址
            String downloadPath = localPath + StringUtils.substringAfter(str, Constants.RESOURCE_PREFIX);
            File f = new File(downloadPath);
            transMsg.setMsgSize(f.length());
            transMsg.setFromNode(sysDept.getDeptId());
            transMsg.setFromType(0L);
            transMsg.setFromId(currentUser.getUserId());
            try {
                transMsg.setMsgMd5(Util.fileMD5Str(f));
            } catch (IOException e) {
                log.error(e, "生成文件MD5失败！");
            }
            transMsg.setMsgData(str);
            transMsgService.insertTransMsg(transMsg);

            for (long userId : userList) {
                TransReceiver receiver = new TransReceiver();
                receiver.setMsgId(msgId);
                // 接收对象为用户
                receiver.setRecvType(1L);
                receiver.setRecvId(userId);
                receiver.setRecvNode(sysDeptSet.get(userId));
                transReceiverService.insertTransReceiver(receiver);
            }

            for (long deptId : deptList) {
                TransTask task = new TransTask();
                task.setMsgId(msgId);
                task.setTaskPriority(10L);
                task.setTaskType((long) taskType);
                task.setRecvNode(deptId);
                task.setTaskStatus(0L);
                transTaskService.insertTransTask(task);
            }
        }

        return R.ok(200,"文件发送成功.");
    }

    @ApiOperation("查询传输状态，传入JSONArray")
    @PostMapping("/checkStatus")
    public R<String> checkStatus(@RequestBody JSONArray msgIds) {
        if (CollUtil.isEmpty(msgIds)) {
            return R.fail("消息编号不能为空！");
        }
        List<Integer> set = msgIds.toList(Integer.class).stream()
                .distinct().collect(Collectors.toList());
        List<Pair<Integer, Integer>> map = transTaskService.selectTaskStatusListByMsgIdSet(set);
        if (map.isEmpty()) {
            return R.fail("未查询到数据！");
        }
        return R.ok(JSONUtil.toJsonPrettyStr(map));
    }

    @ApiOperation("响应传输状态")
    @ApiImplicitParam(name = "msgIds", value = "消息编号", required = true, dataType = "String", dataTypeClass = String.class)
    @PostMapping("/ackStatus")
    public R<String> ackStatus(@RequestBody String msgIds) {
        // @todo
        return R.ok(msgIds);
    }


}
